package mt.omid.dimomuth;


import static mt.omid.dimomuth.Module.MOD_STAT_INITED;
import static mt.omid.dimomuth.Module.MOD_STAT_LOADED;
import static mt.omid.dimomuth.Module.MOD_STAT_SHUTDOWN;
import static mt.omid.dimomuth.Module.MOD_STAT_STARTED;

import java.util.logging.Level;
import java.util.logging.Logger;

import mt.omid.dimomuth.bus.CBMessage;
import mt.omid.dimomuth.bus.DataBus;
import mt.omid.dimomuth.bus.DataBusException;
import mt.omid.dimomuth.statistics.Countable;
import mt.omid.dimomuth.statistics.Counter;
import mt.omid.dimomuth.statistics.StatManager;


public abstract class Process implements Runnable, Countable
{

    //    private BlockingQueue<CBMessage> queue;
    private int       state;
    protected Logger  logger;
    protected int     instId;
    protected DataBus dbus = DataBus.getInstance();
    protected int     id;

    protected Counter msgCounter;
    public final static String msgCounterName = "CBMessage_Recv";


    public Process( Logger lgr, int pid )
    {
	// Check license here to prevent abuse on configuration file
	this.id = pid;
	msgCounter = new Counter( msgCounterName + "/" + this.getClass().getSimpleName() + "#" + pid );
	logger = lgr;
	try
	{
	    DataBus.register( this.id );
	}
	catch( DataBusException e )
	{
	    logger.warning( "Error in registering in data bus: " + e.getMessage() );
	}
	state = MOD_STAT_LOADED;
	instId = Kernel.getInstanceId();
	StatManager.addCountable( this );
    }

    public final void run()
    {
	logger.fine( "Start Process " + this.getClass().getSimpleName() );
	start();
    }

    protected final void start()
    {
	state = MOD_STAT_INITED;
	state = MOD_STAT_STARTED;

	while( state != MOD_STAT_SHUTDOWN )
	{
	    try
	    {
		CBMessage m = dbus.recv( this.id );
		msgCounter.stepUp();
		process( m );
	    }
	    catch( InterruptedException e )
	    {
		logger.info( "Queue taking interrupted." );
		logger.warning( "This thread interrupted so shutting down it." );
		state = MOD_STAT_SHUTDOWN;
	    }
	    catch( ClassCastException cex )
	    {
		logger.log( Level.SEVERE, "Bad message object inserted in queue and now taked.",
			cex );
	    }
	    catch( Throwable t )
	    {
		logger.log( Level.SEVERE,
			"Very Bad Exception or Error. It have to be handled internally not here.",
			t );
	    }
	}
	finishing();
    }

    @Deprecated
    public final void insert( CBMessage msg )
    {
	try
	{
	    msg.rId = this.id;
	    msg.rInst = this.instId;
	    dbus.send( msg );
	}
	catch( InterruptedException e )
	{
	    logger.warning( "The calling thread interrupted so ignoring the message." );
	}
    }

    @Deprecated
    public final boolean insert( CBMessage msg, long to )
    {
	try
	{
	    return dbus.sendNB( msg, to );
	}
	catch( InterruptedException e )
	{
	    logger.warning( "The calling thread interrupted so ignoring the message." );
	    return false;
	}
    }

    public final void shutdown()
    {
	logger.fine( "Shutting down process " + this.getClass().getSimpleName() );
	state = MOD_STAT_SHUTDOWN;
	Thread.currentThread().interrupt();
    }

    public int getId()
    {
	return this.id;
    }
    
    public void resetCounters()
    {
	msgCounter.reset();
    }
    
    public void resetCounter( String name )
    {
	if( name.startsWith( msgCounterName ) )
	    msgCounter.reset();
    }

    public Counter [] getCounters()
    {
	return new Counter [] { msgCounter };
    }
    
    public Counter [] retrieveCounters()
    {
	Counter [] result = new Counter[] { new Counter( msgCounter.getName(), msgCounter.getNum() ) };
	resetCounters();
	return result;
    }

    public abstract void process( CBMessage msg );

    public abstract void finishing();

}
